/*
 * Vinicius Mendes Kastrup Magalhães	-	110092513
 * Thales Teixeira Pires				-	110092474
 */

package main;

import java.util.TreeMap;

public class Kleene {
	private AutomatoFinitoDeterministico afd;
	private String[][] L;
	private int tam;
	private TreeMap<Integer, Estado> indices;
	
	public Kleene(AutomatoFinitoDeterministico afd) {
		this.afd = afd;
		indices = new TreeMap<Integer, Estado>();
		tam = afd.getEstados().size();
		
		int i = 0;
		for(Estado e: this.afd.getEstados()) {
			indices.put(i, e);
			i++;
		}
		
		inicializa();
		montaMatriz();
	}
	
	//inicializa a matriz
	private void inicializa() {
		L = new String[tam][tam];
		for(int i = 0; i < tam; i++) {
			for(int j = 0; j < tam; j++) {
				L[i][j] = indices.get(i).simboloTransicaoPara(indices.get(j));
			}
		}
	}
	
	//monta o restante da matriz
	private void montaMatriz() {
		String parte1, parte2 = "";
		String[][] temp = new String[tam][tam];
		for (int k = 0; k < tam; k++) {
			System.out.println();
			for (int i = 0; i < tam; i++) {
				for (int j = 0; j < tam; j++) {
					
					L[k][k] = parentesis(L[k][k]);
					L[i][j] = parentesis(L[i][j]); 
					L[k][j] = parentesis(L[k][j]);
					L[i][k] = parentesis(L[i][k]);
					parte1 = L[i][j];
					
					if (L[i][k] == "{}" || L[k][j] == "{}") parte2 = "{}";
					else parte2 = L[i][k] + L[k][k] + "*" + L[k][j];
					
					if (i != j) temp[i][j] = limpar(parte1 + "U" + parte2);
					else temp[i][j] = limpar(parte1 + "U" + parte2 + "U{E}");
				}
			}
			L = temp;
		}
	}
	
	//Limpa uma string com muitos parentesis desnecessários
	private String limpar(String s) {
		String[] splitU = s.split("U");
		for (int i = 0; i < splitU.length; i++) {
			splitU[i] = splitU[i].replace("{}*", "");
			if (splitU[i].contains("{}")) splitU[i] = "";
		}
		s = "";
		for (int i = 0; i < splitU.length; i++) {
			if (s.equals("")) {
				s = splitU[i];
			} else {
				if (!splitU[i].equals("")) s += "U" + splitU[i];
			}
		}
		if (s.equals("")) s = "{}";
		return parentesis(s);
	}
	
	//retorna a expressão regular correspondente às posições da matriz
	public String expressaoRegular() {
		String exp = "";
		int i = indiceEi();
		for (int j: indicesEf()) {
			if (exp.equals("")) {
				exp = "(" + L[i][j] + ")";
			} else {
				exp += "U(" + L[i][j] + ")";
			}
		}
		return exp;
	}
	
	private String parentesis(String s) {
		boolean temParentesis = false;
		if (!s.equals("")) temParentesis = s.charAt(0) == '(' && s.charAt(s.length()-1) == ')';
		if (!temParentesis) {
			if (s.length() > 1) s = "(" + s + ")";
		} else {
			if (s.length() == 3) s = s.charAt(1)+"";
			if (s.length() == 4 && s.contains("*")) s = s.charAt(1)+s.charAt(2)+"";
		}
		if (s.equals("({})")) s = "{}"; 
		return s;
	}
	
	//retorna o indice da matriz correspondete ao estado inicial
	private int indiceEi() {
		for (int i: indices.keySet()) {
			if (indices.get(i).getEstado().equals(afd.getEstadoInicial().getEstado())) {
				return i;
			}
		}
		return -1;
	}

	//retorna o indice da matriz correspondete ao estado final
	private int[] indicesEf() {
		int[] indicesF = new int[afd.getEstadosFinais().size()];
		int j = 0;
		for (int i = 0; i < indices.keySet().size(); i++) {
			if (indices.get(i).isFinal()) {
				indicesF[j] = i;
			}
		}
		return indicesF;
	}
}
